#include<iostream>
#include<unistd.h>
#include<cstdio>
#include<cstring>
#include<string>
#include<wait.h>
using namespace std;

const int basesize = 1024;
const int argvnum = 64;
const int envnum = 64;

char* argv[argvnum];
int argc = 0;

char* env[envnum];
int lastcode = 0;

char pwd[basesize];
char pwdenv[basesize];

string GetUserName()
{
    char* name = getenv("USER");
    return name;
}

string GetHostName()
{
    char* name = getenv("HOSTNAME");
    return name;
}


string GetPwd()
{
    if(nullptr == getcwd(pwd,sizeof(pwd))) return "None";
    snprintf(pwdenv,sizeof(pwdenv),"PWD=%s",pwd);
    putenv(pwdenv);
    
    for(int i = 0; env[i]; i++)
    {
        string tmp = env[i];
        if(strcmp(tmp.substr(0,3).c_str(),"PWD") == 0)
        {
            free(env[i]);
            env[i] = (char*)malloc(strlen(pwdenv)+1);
            strncpy(env[i],pwdenv,strlen(pwdenv)+1);
            break;
        }
    }
    //cout << pwdenv << endl; 
    return pwd;

    //char* name = getenv("PWD");
    //return name;
}

string LastDir()
{
    string current = GetPwd();
    if(current == "/" || current == "None") return current;
    size_t pos = current.rfind('/');
    if(pos == std::string::npos) return current;
    return current.substr(pos+1);
}

string MakeCommandLine()
{
    char command_line[basesize];
    snprintf(command_line,basesize,"[%s @%s %s]# ",\
             GetUserName().c_str(),GetHostName().c_str(),LastDir().c_str() );
    return command_line;
}

void PrintCommandLine()
{
    printf("%s",MakeCommandLine().c_str());
    fflush(stdout); 
}


bool GetCommandLine(char command_buffer[])
{
    char* result = fgets(command_buffer,basesize,stdin);
    if(result == nullptr)
        return false;
    command_buffer[strlen(command_buffer) - 1] = 0;
    if(strlen(command_buffer) == 0) return false;
    return true;
}

void ParseCommandLine(char command_buffer[], int size)
{
    (void)size;
    argc = 0;
    memset(argv,0,sizeof(argv)); 
    argv[argc] = strtok(command_buffer," "); 
    
    while((bool)(argv[++argc] = strtok(nullptr," ")));
    
}

bool ExecuteCommand()
{
    pid_t id = fork();

    if(id < 0)  return false;
    else if(id == 0)
    {
        execvpe(argv[0],argv,env);
        exit(1);
    }
    
    int status = 0;
    pid_t rid = waitpid(id,&status,0);
    if(rid > 0)
    {
        if(WIFEXITED(status))
        {
            lastcode = WEXITSTATUS(status);                        
        }
        else 
        {
            lastcode = 100;
        }
        return true;
    }
    return false;
}

void AddEnv(const char* item)
{
   int index = 0;
   while(env[index])
       index++;
   env[index] = (char*)malloc(strlen(item)+1);
   strncpy(env[index],item,strlen(item)+1);
   env[++index] = nullptr;
}

bool CheckAndExecBuiltCommand()
{
    if(strcmp(argv[0],"cd") == 0)
    {
        if(argc == 2)
        {
            chdir(argv[1]);
            lastcode = 0;
        }
        else 
        {
            lastcode = 1;
        }
        return true;
    }
    else if(strcmp(argv[0],"export") == 0)
    {
        if(argc == 2)
        {
            AddEnv(argv[1]);
            lastcode = 0;
        }
        else 
        {
            lastcode = 2;
        }
        return true;
    }
    else if(strcmp(argv[0],"env") == 0)
    {
        for(int i = 0; env[i]; i++)
        {
            printf("%s\n",env[i]);
        }
        lastcode = 0;
        return true;
    }
    else if(strcmp(argv[0],"echo") == 0)
    {
        if(argc == 2)
        {
            if(argv[1][0] == '$')
            {
                if(argv[1][1] == '?')
                {
                    printf("%d\n",lastcode);
                    lastcode = 0;
                }
            }
            else 
            {
                printf("%s\n",argv[1]);
                lastcode = 0;
            }

            lastcode = 0;
        }
        else 
        {
            lastcode = 3;
        }
        return true;
    }
    return false;
}

void InitEnv()
{
    extern char** environ;
    int index = 0;
    while(environ[index])
    {
        env[index] = (char*)malloc(strlen(environ[index]) + 1);
        strncpy(env[index],environ[index],strlen(environ[index]+1));
        ++index;
    }
    env[index] = nullptr;
}

int main()
{
    InitEnv();
    char command_buffer[basesize];
    while(1)
    {

        //打印命令行
        PrintCommandLine();
  
        //获取指令
        if( !GetCommandLine(command_buffer) )
        {
            continue;
        }
        
        //printf("%s\n",command_buffer);

        //解析指令
        ParseCommandLine(command_buffer,strlen(command_buffer));
        
        if(CheckAndExecBuiltCommand())
        {
            continue;
        }

        //执行指令
        ExecuteCommand();    
        
        
    }

    return 0;

}
